package com.irdstudio.apicenter.gateway.comm.pack;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.irdstudio.apicenter.gateway.comm.MaccsPacket;
import com.irdstudio.apicenter.gateway.comm.MaccsPacketUtil;
import com.irdstudio.apicenter.gateway.core.dm.AppChannelForward;
import com.irdstudio.apicenter.gateway.util.crypt.EncryptionUtil;
import com.irdstudio.apicenter.gateway.util.date.CurrentDateUtil;
import com.irdstudio.apicenter.gateway.util.pub.KeyUtil;
import com.irdstudio.apicenter.gateway.web.MaccsTradeDefineVo;

/**
 * 海尔项目组http协议下XML组/解包处理处理类
 * @author zs.ligm
 * @version 1.0
 * @date 2015-10-13
 */
@Service(value="HaierXmlPackProcessor")
public class HaierXmlPackProcessor extends AbstracePackProcessor{

	/* 文本日志记录对象(Logback对象) */
	private final static Logger logger = LoggerFactory
			.getLogger(JsonPackProcessor.class);	

	/**
	 * 解析返回的字符串，组成符合maccs要求的数据包
	 */
	@Override
	public MaccsPacket getReadPackage(AppChannelForward acf,
			MaccsTradeDefineVo tradeDefine, String result) {
		
		MaccsPacket backPacket = null;
		ObjectMapper mapper = new ObjectMapper();
		
		//允许出现特殊字符和转义符
		mapper.configure(Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true) ;
		
		//允许出现单引号
		mapper.configure(Feature.ALLOW_SINGLE_QUOTES, true) ;
		
		//如果是海尔指定的TCP方式，则不按Json解析
		//modified by tangxun on 2015/9/23
//		Map<String, Object> tempMap = new HashMap<String, Object>();
//		tempMap.put("value", result);
//		backPacket = new MaccsPacket(tempMap);
		backPacket = formatResponseJson(result,tradeDefine);
		return backPacket;
	}

	/**
	 * 组装成用于发送的JSON字符串
	 */
	@Override
	public String getSendPackage(AppChannelForward acf,
			MaccsTradeDefineVo tradeDefine, MaccsPacket inUvo) {
		
		//将待发送数据转化为XML格式，再封装
		//转化XML
		logger.info("注册姓名："+inUvo.getValue("userName"));
		String tempXmlStr = formatRequestXML(acf,inUvo,tradeDefine);
//		String tempXmlStr = "000491<?xml version=\"1.0\" encoding=\"UTF-8\" ?><request><head><tradeCode>100002</tradeCode><serno>20150927150407227</serno><sysFlag>04</sysFlag><tradeType></tradeType><tradeDate>2015-09-27</tradeDate><tradeTime>15:04:07</tradeTime><channelNo>05</channelNo><cooprCode></cooprCode></head><body><appId>2001</appId><userName>你好小样的</userName><shareAppId></shareAppId><passWord>12345678</passWord><mobileNo>12345678901</mobileNo><registTime>2015-9-25</registTime></body></request>";
		
		// 封装
		Map<String,Object> sendMap = new HashMap<String,Object>();
		sendMap.put("value", tempXmlStr);
		MaccsPacket requestMsg = new MaccsPacket(sendMap);
		
		// 组装成要发送的字符串({value,XML字符串})
		String msgBody = "";
		msgBody = MaccsPacketUtil.makeFixedString(requestMsg);
		StringBuffer msg = new StringBuffer(acf.getChannelHeadDefine())
				.append(msgBody);
		
		logger.info("发送信息(目标)：" + msg);
		return msg.toString();
	}
	
	//将传入的JSON格式的参数转化为信贷系统能识别的XML格式
	//head+body
	private String formatRequestXML(AppChannelForward acf,MaccsPacket inUvo,MaccsTradeDefineVo tradeDefine){
//		String rtStr = "";
		EncryptionUtil encryptionUtil=new EncryptionUtil();
		// 3.将要发送的内容组装成XML报文
		StringBuffer sendXmlMsg = new StringBuffer("<?xml version=\"1.0\" encoding=\"").append(acf.getChannelCharset()).append("\" ?>");
		sendXmlMsg.append("<request>");
		// 3.1 根据渠道要求组合成报文体(后续应考虑改为配置)
		sendXmlMsg.append("<head>");
		sendXmlMsg.append("<tradeCode>").append(tradeDefine.getTradeCode()).append("</tradeCode>");
		sendXmlMsg.append("<serno>").append(KeyUtil.createUniqueKey()).append("</serno>");
		sendXmlMsg.append("<sysFlag>").append("04").append("</sysFlag>");
		sendXmlMsg.append("<tradeType>").append("").append("</tradeType>");
		sendXmlMsg.append("<tradeDate>").append(CurrentDateUtil.getTodayDate()).append("</tradeDate>");
		sendXmlMsg.append("<tradeTime>").append(CurrentDateUtil.getCurrentTime()).append("</tradeTime>");
		sendXmlMsg.append("<channelNo>").append("05").append("</channelNo>");
		sendXmlMsg.append("<cooprCode>").append("").append("</cooprCode>");
		sendXmlMsg.append("</head>");
		// 3.2 遍历inUvo，组成要发送的XML的报文体
		sendXmlMsg.append("<body>");
		for (Iterator<?> iter = inUvo.getMap().keySet().iterator(); iter
				.hasNext();) {
			String f = (String) iter.next();
			if(("passWord").equals(f)||("password").equals(f)||("oldPassWord").equals(f)||("newpassWord").equals(f)){
				System.out.println("加密前：：："+inUvo.getValue(f));
				//inUvo.addVariable(f, encryptionUtil.encrypt(inUvo.getValue(f)));
				inUvo.merge(f, encryptionUtil.encrypt(inUvo.getValue(f)));
				System.out.println("加密后：：："+inUvo.getValue(f));
			}
			if(f.equalsIgnoreCase("<list>")) {
				sendXmlMsg.append("<list>");
				sendXmlMsg.append(inUvo.getValue(f));
				sendXmlMsg.append("</list>");
			}else{
				sendXmlMsg.append("<").append(f).append(">");				
				String tempXmlStr = inUvo.getValue(f);
				String charset = acf.getChannelCharset(); 
		//		String charset = "gb2312"; 
				byte[] b;
				try {
					b = tempXmlStr.getBytes(charset);
					tempXmlStr = new String(b,charset);
				} catch (UnsupportedEncodingException e) {
					// TODO Auto-generated catch block
					logger.error("change charset to " +charset+ " failed");
					e.printStackTrace();
				} 				
				sendXmlMsg.append(inUvo.getValue(f));
				sendXmlMsg.append("</").append(f).append(">");
			}		
		}
		sendXmlMsg.append("</body>");
		sendXmlMsg.append("</request>");

		// 3.3 组成完整的XML报文(6位长度+报文)
		String msgLength = "000000" + sendXmlMsg.toString().getBytes().length;
		StringBuffer fullXmlMsg = new StringBuffer();
		fullXmlMsg.append(msgLength.substring(msgLength.length() - 6));
		fullXmlMsg.append(sendXmlMsg);		
		
		return fullXmlMsg.toString();
	}
	
	private MaccsPacket formatResponseJson(String backMsg,MaccsTradeDefineVo tradeDefine){
		// 7.将接收到的数据转换为Map对象并封装成MaccsPacket返回
		XmlMapper xmlMapper = new XmlMapper();	
		
		//处理list里的数组，预定list子标签只有ref、info、goods三种
		int i = 1;
		while(backMsg.indexOf("<ref>")>0 || backMsg.indexOf("<info>")>0 || backMsg.indexOf("<goods>")>0){
			backMsg = backMsg.replaceFirst("<ref>", "<ref"+i+">");
			backMsg = backMsg.replaceFirst("</ref>", "</ref"+i+">");
			backMsg = backMsg.replaceFirst("<info>", "<info"+i+">");
			backMsg = backMsg.replaceFirst("</info>", "</info"+i+">");
			backMsg = backMsg.replaceFirst("<goods>", "<goods"+i+">");
			backMsg = backMsg.replaceFirst("</goods>", "</goods"+i+">");
			i++;
		}			
		
	//	backMsg = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><reponse>       <head>              <retFlag>0000</retFlag>              <retMsg>11111111</retMsg>       </head>       <body>              <applCde>111111111</applCde>       </body></reponse>";
		Map<String, Object> backXmlMap = null;
		try {
			backXmlMap = xmlMapper.readValue(backMsg, Map.class);
		} catch (JsonParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JsonMappingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// 7.1 判断返回的报文是否符合要求
		if (backXmlMap == null 
				|| backXmlMap.get("head") == null
				|| !(backXmlMap.get("head") instanceof HashMap<?, ?>)
				|| backXmlMap.get("body") == null
				|| !(backXmlMap.get("body") instanceof HashMap<?, ?>)) {
			logger.error("收到的报文不符合格式要求!");
			return MaccsPacketUtil.makeFailurePacket("收到的报文不符合格式要求!");
		}
		// 7.2 将接收到XML报文头信息转换为移动应用前端能识别的报文
		Map<String,Object> rspHead = (Map<String, Object>) backXmlMap.get("head");
		Map<String,Object> rspBody = (Map<String, Object>) backXmlMap.get("body");
		if("0000".equals(rspHead.get("retFlag"))){
			rspBody.put("ec", MaccsPacketUtil.SUCCESS_FLAG);
		} else {
			rspBody.put("ec", rspHead.get("retFlag"));
		}
		rspBody.put("em", rspHead.get("retMsg"));
		// 7.3 返回给前端响应的数据(报文头经过转换后成为报文体MAP对象中的一部分
		MaccsPacket backPacket = new MaccsPacket(rspBody);		
		
		return backPacket;
	}	
}
